package main

import (
	"bytes"
	"fmt"
	"go/parser"
	"go/token"
	"io/fs"
	"log"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	transformers_utils "github.com/nucleuscloud/neosync/worker/pkg/benthos/transformers"
)

type TransformerInfo struct {
	Name string
	Type string
}

func main() {
	args := os.Args
	if len(args) < 1 {
		panic("must provide necessary args")
	}

	packageName := args[1]
	fileSet := token.NewFileSet()
	transformers := []string{}
	generators := []string{}

	err := filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error {
		if !d.IsDir() && filepath.Ext(path) == ".go" {
			node, err := parser.ParseFile(fileSet, path, nil, parser.ParseComments)
			if err != nil {
				log.Printf("Failed to parse file %s: %v", path, err)
				return nil
			}
			for _, cgroup := range node.Comments {
				for _, comment := range cgroup.List {
					if strings.HasPrefix(comment.Text, "// +neosyncTransformerBuilder:") {
						parts := strings.Split(comment.Text, ":")
						if len(parts) < 3 {
							continue
						}
						if parts[1] == "transform" {
							transformers = append(transformers, fmt.Sprintf("New%s()", transformers_utils.CapitalizeFirst(parts[2])))
						} else if parts[1] == "generate" {
							generators = append(generators, fmt.Sprintf("New%s()", transformers_utils.CapitalizeFirst(parts[2])))
						}
					}
				}
			}
		}
		return nil
	})
	if err != nil {
		log.Fatalf("impossible to walk directories: %s", err)
	}
	codeStr, err := generateCode(transformers, generators, packageName)
	if err != nil {
		fmt.Println("Error creating code:", err)
		return
	}
	output := "gen_neosync_transformers.go"
	outputFile, err := os.Create(output)
	if err != nil {
		fmt.Println("Error creating output file:", err)
		return
	}

	_, err = outputFile.WriteString(codeStr)
	if err != nil {
		fmt.Println("Error writing to output file:", err)
		return
	}
	outputFile.Close()

}

const codeTemplate = `
// Code generated by Neosync neosync_transformer_list_generator.go. DO NOT EDIT.

package {{.PackageName}}

func GetNeosyncTransformers() []NeosyncTransformer {
	return []NeosyncTransformer{
	{{- range $index, $transformer := .Transformers }}
		{{$transformer}},
	{{- end }}
	}
}

func GetNeosyncGenerators() []NeosyncGenerator {
	return []NeosyncGenerator{
		{{- range $index, $generator := .Generators }}
			{{$generator}},
		{{- end }}
	}
}
`

type TemplateData struct {
	Transformers []string
	Generators   []string
	PackageName  string
}

func generateCode(transformers, generators []string, pkgName string) (string, error) {
	data := TemplateData{
		Transformers: transformers,
		Generators:   generators,
		PackageName:  pkgName,
	}
	t := template.Must(template.New("neosyncTransformerList").Parse(codeTemplate))
	var out bytes.Buffer
	err := t.Execute(&out, data)
	if err != nil {
		return "", err
	}
	return out.String(), nil
}
